/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       buy_building_window.cpp

	$Header: /game/buy_building_window.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "buy_building_window.h"

#include "adaptor_handler.h"
#include "adventure_map.h"
#include "basic_dialog.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "building_traits.h"
#include "button_cache.h"
#include "buy_building_detail.h"
#include "elements_of.h"
#include "external_string.h"
#include "format_string.h"
#include "interface_help.h"
#include "player.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "town.h"

static t_bitmap_group_cache g_interface( "dialog.buy_building" );
static t_bitmap_group_cache g_life_thumbnails( "town.life.thumbnails" );
static t_bitmap_group_cache g_order_thumbnails( "town.order.thumbnails" );
static t_bitmap_group_cache g_death_thumbnails( "town.death.thumbnails" );
static t_bitmap_group_cache g_chaos_thumbnails( "town.chaos.thumbnails" );
static t_bitmap_group_cache g_nature_thumbnails( "town.nature.thumbnails" );
static t_bitmap_group_cache g_might_thumbnails( "town.might.thumbnails" );

static t_external_string const k_text_town_hall_title ( "town_hall.title" );
static t_external_string const k_text_disabled_building( "disabled_building.dialog" );

extern t_button_cache       g_ok_button;

t_bitmap_group_cache* g_building_thumbnails[] =
{
	&g_life_thumbnails, &g_order_thumbnails, &g_death_thumbnails, 
	&g_chaos_thumbnails, &g_nature_thumbnails, &g_might_thumbnails 
};

namespace
{
	enum t_button_state
	{
		k_button_hidden,
		k_button_built,
		k_button_disabled,
		k_button_cannot_build,
		k_button_cannot_afford,
		k_button_not_owner,
		k_button_ok
	};

	struct t_button_info
	{
		t_button_state state;
		int            id;
	};

	enum
	{
		k_row_1 = 0,
		k_row_2 = 4,
		k_row_3 = 8,
		k_row_4 = 12,
		k_row_5 = 16,
		k_max_buttons = 20
	};

	struct t_button_map
	{
		int	id;
		int button_id;
	};

	t_button_map const k_common_buttons[] =
	{
		{ k_town_village_hall,	k_row_1 },
		{ k_town_hall,			k_row_1 },
		{ k_town_city_hall,		k_row_1 },
		{ k_town_fort,			k_row_1 + 1 },
		{ k_town_citadel,		k_row_1 + 1 },
		{ k_town_castle,		k_row_1 + 1 },
		{ k_town_tavern,		k_row_1 + 2 },
		{ k_town_blacksmith,	k_row_1 + 3 },
		{ k_town_dwelling_1,	k_row_2 },
		{ k_town_dwelling_2,	k_row_3 },
		{ k_town_dwelling_3,	k_row_2 + 1 },
		{ k_town_dwelling_4,	k_row_3 + 1 },
		{ k_town_dwelling_5,	k_row_2 + 2 },
		{ k_town_dwelling_6,	k_row_3 + 2 },
		{ k_town_dwelling_7,	k_row_2 + 3 },
		{ k_town_dwelling_8,	k_row_3 + 3 },
		{ k_town_caravan,		k_row_5 },
		{ k_town_shipyard,		k_row_5 + 1 },
	};

	t_button_map const k_life_buttons[] =
	{
		{ k_town_mage_guild_1,	k_row_4 },
		{ k_town_mage_guild_2,	k_row_4 },
		{ k_town_mage_guild_3,	k_row_4 },
		{ k_town_mage_guild_4,	k_row_4 },
		{ k_town_mage_guild_5,	k_row_4 },
		{ k_town_library_1,		k_row_4 + 1 },
		{ k_town_library_2,		k_row_4 + 2 },
		{ k_town_stables,		k_row_4 + 3 },
		{ k_town_abbey,			k_row_5 + 2 },
		{ k_town_seminary,		k_row_5 + 3 },
	};

	t_button_map const k_order_buttons[] =
	{
		{ k_town_mage_guild_1,	k_row_4 },
		{ k_town_mage_guild_2,	k_row_4 },
		{ k_town_mage_guild_3,	k_row_4 },
		{ k_town_mage_guild_4,	k_row_4 },
		{ k_town_mage_guild_5,	k_row_4 },
		{ k_town_library_1,		k_row_4 + 1 },
		{ k_town_library_2,		k_row_4 + 2 },
		{ k_town_treasury,		k_row_5 + 2 },
		{ k_town_university,	k_row_5 + 3 },
	};

	t_button_map const k_death_buttons[] =
	{
		{ k_town_mage_guild_1,	k_row_4 },
		{ k_town_mage_guild_2,	k_row_4 },
		{ k_town_mage_guild_3,	k_row_4 },
		{ k_town_mage_guild_4,	k_row_4 },
		{ k_town_mage_guild_5,	k_row_4 },
		{ k_town_library_1,		k_row_4 + 1 },
		{ k_town_library_2,		k_row_4 + 2 },
		{ k_town_necromancy_amplifier,	k_row_4 + 3 },
		{ k_town_skeleton_transformer,	k_row_5 + 2 },
	};

	t_button_map const k_chaos_buttons[] = 
	{
		{ k_town_mage_guild_1,	k_row_4 },
		{ k_town_mage_guild_2,	k_row_4 },
		{ k_town_mage_guild_3,	k_row_4 },
		{ k_town_mage_guild_4,	k_row_4 },
		{ k_town_mage_guild_5,	k_row_4 },
		{ k_town_library_1,		k_row_4 + 1 },
		{ k_town_library_2,		k_row_4 + 2 },
		{ k_town_mana_vortex,	k_row_4 + 3 },
		{ k_town_academy,		k_row_5 + 2 },
		{ k_town_training_grounds,	k_row_5 + 3 },
	};

	t_button_map const k_nature_buttons[] =
	{
		{ k_town_mage_guild_1,	k_row_4 },
		{ k_town_mage_guild_2,	k_row_4 },
		{ k_town_mage_guild_3,	k_row_4 },
		{ k_town_mage_guild_4,	k_row_4 },
		{ k_town_mage_guild_5,	k_row_4 },
		{ k_town_library_1,		k_row_4 + 1 },
		{ k_town_library_2,		k_row_4 + 2 },
		{ k_town_portal,		k_row_4 + 3 },
		{ k_town_rainbow,		k_row_5 + 2 },
		{ k_town_grove,			k_row_5 + 3 }
	};

	t_button_map const k_might_buttons[] =
	{
		{ k_town_breeding_pit,		k_row_4 + 3 },
		{ k_town_magic_dampener,	k_row_4 + 2 },
		{ k_town_arena,				k_row_4 + 1 },
		{ k_town_training_grounds,	k_row_4 }
	};

	struct t_button_array
	{
		t_button_map const* map;
		int                 count;
	};

	t_button_array const k_button_maps[] =
	{
		{ k_life_buttons,		ELEMENTS_OF( k_life_buttons ) },
		{ k_order_buttons,		ELEMENTS_OF( k_order_buttons ) },
		{ k_death_buttons,		ELEMENTS_OF( k_death_buttons ) },
		{ k_chaos_buttons,		ELEMENTS_OF( k_chaos_buttons ) },
		{ k_nature_buttons,	ELEMENTS_OF( k_nature_buttons ) },
		{ k_might_buttons,		ELEMENTS_OF( k_might_buttons ) }
	};

    const int k_building_columns = 4;
}; // unnamed namespace

// -------------------------------------------------------------------
// dialog for purchasing buildings in town
// -------------------------------------------------------------------
t_buy_building_window::t_buy_building_window( t_town* town, t_window* parent )
					 : t_window( k_no_transparency, parent ), m_town( town )
{
	m_interface = g_interface.get();
	t_help_block const& help = get_help_block( "town_hall" );

	// put up background
	t_window*             background;
	t_bitmap_layer const* background_layer;

	background_layer = m_interface->find( "background" );
	background = new t_bitmap_layer_window( background_layer, t_screen_point(0,0), this );

    // Text windows.
    t_text_window*  text_window_ptr;
	t_screen_rect   rect;

	rect = m_interface->find( "title" )->get_rect();
	text_window_ptr  = new t_text_window( get_font( rect.height() ), rect, this, "", t_pixel_24(0,0,0) );
    text_window_ptr->set_text ( k_text_town_hall_title );
	text_window_ptr->set_center_horizontal();

	// add OK button
	t_button*             button;
	t_bitmap_layer const* layer;

	layer = m_interface->find( "ok_button" );
	button = new t_button( g_ok_button.get(), layer->get_rect().top_left(), background );
	button->set_click_handler( bound_handler( *this, &t_buy_building_window::close_click ) );
  set_help( button, help, "ok" );

	create_buttons( background );

	m_material_display.init( m_interface, &town->get_map()->get_player(), t_screen_point(0,0),
		                     background );

	// figure out the client coordinates for this window
	// center it
	t_screen_rect background_rect = background->get_client_rect();
	background_rect += t_screen_point( (parent->get_width() - background_rect.width()) / 2, 
		                               (parent->get_height() - background_rect.height()) / 2 );
	init( background_rect );
	set_drop_shadow();
}

// -------------------------------------------------------------------
// set states of buttons
// -------------------------------------------------------------------
void set_button_state( t_button_info* button_info, t_town const* town,
					   t_button_map const* button_map, int count )
{
	int             i;
	t_town_building building;
	t_button_info*  info;
	t_button_state  state;
	t_adventure_map & map = *town->get_map();
	int             player_number = map.get_player_number();

	for (i = 0; i < count; i++)
	{
		building = t_town_building( button_map[i].id );
		if (!town->is_legal( building ))
			continue;

		info = button_info + button_map[i].button_id;

		if (town->has( building ))
			state = k_button_built;
		else if (!town->is_enabled( building ))
			state = k_button_disabled;
		else if ( player_number != town->get_owner_number() )
			state = k_button_not_owner;
		else if (!town->can_build( building ))
			state = k_button_cannot_build;
		else if (!town->can_afford( building ))
			state = k_button_cannot_afford;
		else if (town->has_built())
			state = k_button_cannot_build;
		else
			state = k_button_ok;
		if (state < info->state)
			continue;
		if (state == info->state && state != k_button_built)
			continue;

		info->state = state;
		info->id = building;
	}
}

// -------------------------------------------------------------------
// dialog for purchasing buildings in town
// create buttons for purchasing buildings.
// -------------------------------------------------------------------
void t_buy_building_window::create_buttons( t_window* background )
{
	t_button_info button_info[k_max_buttons];
	t_town_type   town_type = m_town->get_type();
	t_help_block const& help = get_help_block( "town_hall" );

	int i;

	for (i = 0; i < k_max_buttons; i++)
	{
		button_info[i].id = -1;
		button_info[i].state = k_button_hidden;
	}

	set_button_state( button_info, m_town, k_common_buttons, ELEMENTS_OF( k_common_buttons ));
	set_button_state( button_info, m_town, k_button_maps[town_type].map, 
	                  k_button_maps[town_type].count );

	t_bitmap_layer const* layer;
	t_button*			  button;
	t_bitmap_layer const* frame = m_interface->find( "frame" );
	t_screen_point        frame_origin = frame->get_rect().top_left();
	t_bitmap_layer const* thumbnail = m_interface->find( "thumbnail" );
	t_screen_point        thumbnail_origin = thumbnail->get_rect().top_left() - frame_origin;
	t_bitmap_layer const* x_mark = m_interface->find( "cannot build" );
	t_bitmap_layer const* bars[6];
	t_window*             frame_window;
	t_window*             window;
	t_town_building       building;

	m_thumbnails = g_building_thumbnails[town_type]->get();

	bars[k_button_disabled - 1]		 = m_interface->find( "gray bar" );
	bars[k_button_built - 1]		 = m_interface->find( "gold bar" );
	bars[k_button_cannot_build - 1]	 = m_interface->find( "red bar" );
	bars[k_button_cannot_afford - 1] = bars[k_button_cannot_build - 1];
	bars[k_button_not_owner - 1]     = bars[k_button_cannot_build - 1];
	bars[k_button_ok - 1]			 = m_interface->find( "green bar" );

	// find row rectangles
	t_bitmap_layer const* rows[5];
	int                   row_counts[5];
	int                   row_spacing[5];
	int                   row_start[5];

	for (i = 0; i < 5; i++)
	{
		row_counts[i] = 0;
		rows[i] = m_interface->find( format_string( "row %i", i + 1 ) );
	}

	// count # of buttons in each row
	for (i = 0; i < 20; i++)
		if (button_info[i].state != k_button_hidden)
			row_counts[i / 4]++;

	// compute row spacing
    int             width_diff;
	for (i = 0; i < 5; i++)
	{
        // Diff. between row frame and sum of individual building frames.
        width_diff = (rows[i]->get_width() - k_building_columns * frame->get_width());

		row_spacing[i] = width_diff / (k_building_columns - 1) + frame->get_width();
		row_start[i] =  (rows[i]->get_width() - frame->get_width() 
			             - row_spacing[i] * (row_counts[i] - 1)) / 2;
	}             

	// create the buttons
	t_screen_point  point;
	int             row;
	t_window*       bar;
	t_text_window*  text_window;
	t_screen_rect   rect;
	t_screen_rect   text_rect = m_interface->find("building_text")->get_rect();

	//t_screen_point  thumbnail_offset;

	for (i = 0; i < k_max_buttons; i++)
	{
		if (button_info[i].state == k_button_hidden)
			continue;

		building = t_town_building( button_info[i].id  );

		t_building_traits const& traits = get_traits( town_type, building );

		row = i / k_building_columns;
		point = rows[row]->get_rect().top_left();
		point.x += row_start[row] + (i % k_building_columns ) * row_spacing[row];
		button = new t_button( point, background );
		
        rect = frame->get_rect() - frame->get_rect().top_left();
	    frame_window = new t_window ( rect, k_completely_transparent, button );
		window = new t_bitmap_layer_window( frame, -frame->get_rect().top_left(), frame_window );

		// add thumbnail
		layer = m_thumbnails->find( traits.keyword );
		window = new t_bitmap_layer_window( layer, thumbnail_origin, frame_window );

		// if cannot build, add X mark
		switch (button_info[i].state)
		{
			case k_button_disabled:
			case k_button_cannot_build:
			case k_button_cannot_afford:
				window = new t_bitmap_layer_window( x_mark, -frame_origin, frame_window );
				break;
		}
		
		// add appropriate bar
		t_bitmap_layer const* bar_layer = bars[button_info[i].state - 1];
		bar = new t_bitmap_layer_window( bar_layer, -frame_origin, frame_window );
		
		// add name to bar
		text_window = new t_text_window( get_font( text_rect.height() / 2 ), text_rect - bar_layer->get_rect().top_left(),
			                             bar, traits.name, t_pixel_24(0, 0, 0) );
		text_window->set_center_horizontal();
		text_window->set_center_vertical();
		//text_window->set_drop_shadow( true );

		switch (button_info[i].state)
		{
            case k_button_built:
	            set_help( button, help, "gold_bar" );
                break;

			case k_button_disabled:
	            set_help( button, help, "gray_bar" );
                break;

			case k_button_cannot_build:
	            set_help( button, help, "red_bar_x" );
                break;

			case k_button_cannot_afford:
	            set_help( button, help, "red_bar_$" );
				break;

			case k_button_not_owner:
				set_help( button, help, "red_bar_owner" );
				break;

            default :
	            set_help( button, help, "green_bar" );
				break;
		}
		
		// set image and handler
	    frame_window->set_size_from_children();
		button->set_released_image( frame_window );
		if (button_info[i].state == k_button_disabled)
        {
		    button->set_click_handler( add_2nd_argument(
			    bound_handler( *this, &t_buy_building_window::disabled_building_click ), button_info[i].id ));
        }
        else
        {
		    button->set_click_handler( add_2nd_argument(
			    bound_handler( *this, &t_buy_building_window::building_click ), button_info[i].id ));
        }
		button->set_right_click_handler( add_2nd_argument(
			bound_handler( *this, &t_buy_building_window::describe_building ), button_info[i].id ));
	}
}

// -------------------------------------------------------------------
// dialog for purchasing buildings in town
// -------------------------------------------------------------------
void t_buy_building_window::close_click( t_button* )
{
	m_return_value = k_town_no_building;
	close();
}

// -------------------------------------------------------------------
// dialog for purchasing buildings in town
// -------------------------------------------------------------------
void t_buy_building_window::building_click( t_button*, int building )
{
	t_window_ptr window = new t_buy_building_detail( m_town, t_town_building(building), this );

	if (window->run_modal() == 0)
		return;

	m_return_value = building;
	close();
}

// -------------------------------------------------------------------
// dialog for purchasing buildings in town
// -------------------------------------------------------------------
void t_buy_building_window::disabled_building_click( t_button*, int building )
{
	t_counted_ptr<t_basic_dialog> dialog = new t_basic_dialog(this);

	dialog->set_text( k_text_disabled_building );
	dialog->add_ok_button();
	dialog->open();
	dialog->run_modal();
}

// ----------------------------------------------------
// Display a simple description of a building for
// a right-click
// NOTE:  Duplicated from t_town_window.  Could just call
// that if we had a pointer to the parent town window
// handy...
// ----------------------------------------------------
void t_buy_building_window::describe_building( t_button *button, int building )
{
	t_building_traits const& traits = get_traits( m_town->get_type(), t_town_building(building) );

	t_counted_ptr<t_basic_dialog> dialog = new t_basic_dialog(this);

	dialog->set_text( traits.help_text );
	dialog->add_ok_button();

	dialog->set_title( traits.name );
	
	dialog->open();
	dialog->run_modal();
}
